# -*- coding: utf-8 -*-
# @Time    : 2025/8/10 10:52
# @Author  : FuKai ZHANG
# @File    : swagger_parser.py
# @Description :解析swagger文件
from typing import Dict
import json
from prance import ResolvingParser
import requests

def parse_swagger(swagger_url):
    """
    使用 prance 解析 Swagger JSON，自动展开 $ref。
    """
    try:
        # 尝试多个验证后端以提高兼容性
        backends = ['openapi-spec-validator', 'swagger-spec-validator', 'flex']
        parser = None
        for backend in backends:
            try:
                parser = ResolvingParser(swagger_url, backend=backend)
                break
            except ValueError as e:
                if "No validation backend available" in str(e):
                    continue
                else:
                    raise e
        # 如果没有找到可用的验证后端，抛出明确的错误提示
        if parser is None:
            raise ValueError("无法找到可用的验证后端。请安装以下任一包: pip install openapi-spec-validator 或 pip install swagger-spec-validator 或 pip install flex")
        return parser.specification
    except requests.exceptions.RequestException as e:
        raise ValueError(f"无法下载 Swagger 文档: {e}")
    except Exception as e:
        raise ValueError(f"解析 Swagger 文档失败: {e}")

def extract_operations(spec:Dict)->Dict:
    """
    提取接口信息，按模块（tags）分组。
    """
    operations = {}
    # 提取安全定义
    security_definitions = spec.get('securityDefinitions', {})
    
    #如果不存在 就返回空字典
    paths = spec.get('paths', {})#'paths' 是 OpenAPI 规范中的一个关键字段，包含了 API 的所有路径定义
    # 遍历路径。path 是 URL 路径（如 "/users"），methods 是该路径下所有 HTTP 方法的字典。
    for path, methods in paths.items():
        #这里的 operation是 方法的详细定义
        for method, operation in methods.items():
            if method.lower() not in ['get', 'post', 'patch', 'delete', 'head', 'options']:
                continue  # 只支持指定的方法
            #tags 是接口的标签，一般是模块名
            tags = operation.get('tags', ['default'])
            # 如果无 tags，用 default
            module = tags[0]  # 取第一个 tag 作为模块名
            #
            op_id = operation.get('operationId', f"{method}_{path.replace('/', '_').strip('_')}")
            # 处理 consumes 和 produces (Swagger 2.0)
            consumes = operation.get('consumes', [])  # 请求内容类型
            produces = operation.get('produces', [])  # 响应内容类型
            
            # 检查是否有安全要求
            security = operation.get('security', [])
            
            op_info = {
                'path': path,
                'method': method.upper(),
                'summary': operation.get('summary', ''),
                'consumes': consumes,
                'parameters': operation.get('parameters', []),
                'produces': produces,
                'requestBody': operation.get('requestBody', {}),
                'responses': operation.get('responses', {}),
                'security': security,
                'security_definitions': security_definitions
            }
            if module not in operations:
                operations[module] = {}
            operations[module][op_id] = op_info
    return operations

if __name__ == '__main__':
    spec=parse_swagger('swagger_pet.json')
    operations = extract_operations(spec)
    print("解析到的模块和操作：")
    for module, ops in operations.items():
        print(f"\n模块: {module}")
        for op_id, op_info in ops.items():
            print(f"  操作ID: {op_id}")
            print(f"    路径: {op_info['path']}")
            print(f"    方法: {op_info['method']}")
            print(f"    摘要: {op_info['summary']}")
            print(f"    参数: {op_info['parameters']}")
            print(f"    请求类型: {op_info['consumes']}")
            print(f"    请求体: {op_info['requestBody']}")
            print(f"    响应类型: {op_info['produces']}")
            print(f"    响应: {op_info['responses']}")
            print(f"    安全要求: {op_info['security']}")
            print(f"    安全定义: {op_info['security_definitions']}")